package com.csq.androidproject.views.calendarview.caldroid.views;

import hirondelle.date4j.DateTime;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;

import android.content.Context;
import android.graphics.Color;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.GridView;
import android.widget.TextView;

import com.csq.androidproject.R;
import com.csq.androidproject.utils.DateUtils;
import com.csq.androidproject.views.calendarview.caldroid.SpecialCalendarGridCell;
import com.csq.androidproject.views.calendarview.caldroid.Weekday;
import com.csq.androidproject.views.calendarview.caldroid.adapters.CaldroidGridAdapter;
import com.csq.androidproject.views.calendarview.caldroid.adapters.MonthPagerAdapter;
import com.csq.androidproject.views.calendarview.caldroid.adapters.WeekdayArrayAdapter;
import com.csq.androidproject.views.calendarview.caldroid.listeners.CaldroidListener;
import com.csq.androidproject.views.calendarview.pager.InfinitePagerAdapter;
import com.csq.androidproject.views.calendarview.pager.InfiniteViewPager;

public class CalendarView extends FrameLayout {
    
    /**
     * 常规背景和文字颜色
     */
    public static int normalBackgroundDrawableResId = R.drawable.calendar_cell_bg;
    public static int normalTextColor = Color.BLACK;
    /**
     * 上个月或下个月文字颜色
     */
    public static int disableBackgroundDrawableResId = R.drawable.calendar_disable_cell;
    public static int disabledTextColor = Color.GRAY;
    /**
     * 今天文字背景和颜色
     */
    public static int todayBackgroundDrawableResId = R.drawable.calendar_red_border;
    public static int todayTextColor = Color.RED;
    /**
     * 划屏缓存数量
     */
    public final static int NUMBER_OF_PAGES = 4;
    
    
    private Button leftArrowButton;
    private Button rightArrowButton;
    private TextView monthTitleTextView;
    private GridView weekdayGridView;
    private InfiniteViewPager viewPager;
    
    
    /**
     * 是否显示上月下月箭头
     */
    private boolean showNavigationArrows = true;
    /**
     * 是否可以左右手势滑动
     */
    private boolean enableSwipe = true;
    /**
     * 是否一直显示6行
     */
    private boolean fitAllMonths = true;
    /**
     * 第一列是星期日
     */
    private int startDayOfWeek = Weekday.SUNDAY;
    /**
     * 当前年月
     */
    private DateTime curPageDateTime = null;
    
    
    /**
     * 划屏每页数据适配器
     */
    private ArrayList<CaldroidGridAdapter> pagerAdapters = new ArrayList<CaldroidGridAdapter>();
    /**
     * 当前显示的日期适配器
     */
    private CaldroidGridAdapter curGridAdapter = null;
    /**
     * 特殊日期及相关信息
     */
    private HashMap<String, SpecialCalendarGridCell> specialDates = new HashMap<String, SpecialCalendarGridCell>();
    
    
    /**
     * 划屏监听
     */
    private DatePageChangeListener pageChangeListener;
    /**
     * 日历相关事件监听
     */
    private CaldroidListener caldroidListener;
    /**
     * date cell 点击事件
     */
    private OnItemClickListener dateItemClickListener = new OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            // TODO Auto-generated method stub
            if(caldroidListener != null && curGridAdapter != null){
                DateTime dateTime = null;
                try {
                    dateTime = curGridAdapter.getDatetimeList().get(position);
                }
                catch (Exception e) {
                }
                
                if(dateTime != null 
                    && dateTime.getYear().equals(curPageDateTime.getYear()) 
                    && dateTime.getMonth().equals(curPageDateTime.getMonth())){
                    caldroidListener.onClicked(dateTime, view);
                }
            }
        }
    };
    /**
     * date cell 长按事件
     */
    private OnItemLongClickListener dateItemLongClickListener = new OnItemLongClickListener() {
        @Override
        public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
            // TODO Auto-generated method stub
            if(caldroidListener != null && curGridAdapter != null){
                DateTime dateTime = null;
                try {
                    dateTime = curGridAdapter.getDatetimeList().get(position);
                }
                catch (Exception e) {
                }
                
                if(dateTime != null 
                    && dateTime.getYear().equals(curPageDateTime.getYear()) 
                    && dateTime.getMonth().equals(curPageDateTime.getMonth())){
                    caldroidListener.onLongClicked(dateTime, view);
                    return true;
                }
            }
            return false;
        }
    };
    

    public CalendarView(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
        initViews();
    }
    
    
    private void initViews(){
        
        // 加载
        View view = LayoutInflater.from(getContext()).inflate(R.layout.calendar_view, this, true);
        monthTitleTextView = (TextView) view.findViewById(R.id.calendar_month_year_textview);
        leftArrowButton = (Button) view.findViewById(R.id.calendar_left_arrow);
        rightArrowButton = (Button) view.findViewById(R.id.calendar_right_arrow);
        viewPager = (InfiniteViewPager) view.findViewById(R.id.months_infinite_pager);

        leftArrowButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                prevMonth();
            }
        });

        rightArrowButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                nextMonth();
            }
        });

        //是否显示上下月箭头
        setShowNavigationArrows(showNavigationArrows);

        // 初始化星期
        weekdayGridView = (GridView) view.findViewById(R.id.weekday_gridview);
        WeekdayArrayAdapter weekdaysAdapter = new WeekdayArrayAdapter(
                getContext(), android.R.layout.simple_list_item_1,
                DateUtils.getDaysOfWeek(startDayOfWeek));
        weekdayGridView.setAdapter(weekdaysAdapter);
        
        // 初始化当前时间
        initCurrentData();

        // 添加pagers
        setupDateGridPages();

        // Inform client that all views are created and not null
        // Client should perform customization for buttons and textviews here
        if (caldroidListener != null) {
            caldroidListener.onCaldroidViewCreated();
        }
    }
    
    /**
     * Setup 4 pages contain date grid views. These pages are recycled to use
     * memory efficient
     */
    private void setupDateGridPages() {

        // MonthPagerAdapter
        final MonthPagerAdapter pagerAdapter = new MonthPagerAdapter(getContext());
        ArrayList<PageGridView> pageViews = pagerAdapter.getItems();
        pagerAdapters.clear();
        for (int i = 0,size = pageViews.size(); i < size; i++) {
            PageGridView dateGridFragment = pageViews.get(i);
            CaldroidGridAdapter adapter = new CaldroidGridAdapter(getContext());
            pagerAdapters.add(adapter);
            dateGridFragment.setAdapter(adapter);
            dateGridFragment.setOnItemClickListener(dateItemClickListener);
            dateGridFragment.setOnItemLongClickListener(dateItemLongClickListener);
        }
        // Setup InfinitePagerAdapter to wrap around MonthPagerAdapter
        InfinitePagerAdapter infinitePagerAdapter = new InfinitePagerAdapter(pagerAdapter);
        
        
        // 设置适配器
        viewPager.setAdapter(infinitePagerAdapter);

        // 是否可以滑动
        viewPager.setEnabled(enableSwipe);
        
        // 是否显示6行
        viewPager.setFitAllMonths(fitAllMonths);
        
        // 仅仅根据数据计算高度
        viewPager.setDateInMonthsList(
            DateUtils.getFullWeeks(curPageDateTime.getMonth(), 
                curPageDateTime.getYear(), 
                startDayOfWeek));
        
        // 换页监听
        pageChangeListener = new DatePageChangeListener();
        viewPager.setOnPageChangeListener(pageChangeListener);
        
        //设置刷新数据
        pageChangeListener.refreshAdapters();
    }
    
    /**
     * 初始化当前时间
     */
    private void initCurrentData(){
        DateTime d = DateUtils.convertDateToDateTime(new Date(System.currentTimeMillis()));
        setCurrentPageDateTime(d);
    }
    
    
    
    public void setCurrentPageDateTime(Date date) {
        setCurrentPageDateTime(DateUtils.convertDateToDateTime(date));
    }

    public void setCurrentPageDateTime(DateTime dateTime) {
        curPageDateTime = dateTime;

        monthChanged();
    }
    
    public HashMap<String, SpecialCalendarGridCell> getSpecialDates() {
        return specialDates;
    }

    public void setSpecialDates(List<SpecialCalendarGridCell> dates) {
        specialDates.clear();
        if(dates != null && dates.size() > 0){
            for(SpecialCalendarGridCell s : dates){
                specialDates.put(DateUtils.getYMDString(s.data), s);
            }
        }
        if(pagerAdapters != null){
            for(CaldroidGridAdapter a : pagerAdapters){
                a.updateSpecialDates(specialDates);
            }
        }
    }

    /**
     * 月改变，刷新界面
     */
    private void monthChanged() {
        monthTitleTextView.setText(curPageDateTime.format("MMMM", 
            Locale.getDefault()).toUpperCase() + " " + curPageDateTime.getYear());
        
        // Notify listener
        if (caldroidListener != null) {
            caldroidListener.onChangeMonth(curPageDateTime.getMonth(), curPageDateTime.getYear());
        }
    }
    
    
    /**
     * Set calendar to previous month
     */
    public void prevMonth() {
        viewPager.setCurrentItem(pageChangeListener.getCurrentPage() - 1);
    }

    /**
     * Set calendar to next month
     */
    public void nextMonth() {
        viewPager.setCurrentItem(pageChangeListener.getCurrentPage() + 1);
    }
    
    /**
     * Move calendar to the specified date
     * 
     * @param date
     */
    public void moveToDate(Date date) {
        moveToDateTime(DateUtils.convertDateToDateTime(date));
    }

    /**
     * Move calendar to specified dateTime, with animation
     * 
     * @param dateTime
     */
    public void moveToDateTime(DateTime dateTime) {

        DateTime firstOfMonth = new DateTime(curPageDateTime.getYear(), curPageDateTime.getMonth(), 1, 0, 0, 0, 0);
        DateTime lastOfMonth = firstOfMonth.getEndOfMonth();

        // To create a swipe effect
        // Do nothing if the dateTime is in current month

        // Calendar swipe left when dateTime is in the past
        if (dateTime.lt(firstOfMonth)) {
            // Get next month of dateTime. When swipe left, month will
            // decrease
            DateTime firstDayNextMonth = dateTime.plus(0, 1, 0, 0, 0, 0, 0,
                    DateTime.DayOverflow.LastDay);

            // Refresh adapters
            setCurrentPageDateTime(firstDayNextMonth);
            int currentItem = viewPager.getCurrentItem();
            pageChangeListener.refreshAdapters(currentItem);

            // Swipe left
            viewPager.setCurrentItem(currentItem - 1);
        }

        // Calendar swipe right when dateTime is in the future
        else if (dateTime.gt(lastOfMonth)) {
            // Get last month of dateTime. When swipe right, the month will
            // increase
            DateTime firstDayLastMonth = dateTime.minus(0, 1, 0, 0, 0, 0, 0,
                    DateTime.DayOverflow.LastDay);

            // Refresh adapters
            setCurrentPageDateTime(firstDayLastMonth);
            int currentItem = viewPager.getCurrentItem();
            pageChangeListener.refreshAdapters(currentItem);

            // Swipe right
            viewPager.setCurrentItem(currentItem + 1);
        }

    }
    
    
    public boolean isShowNavigationArrows() {
        return showNavigationArrows;
    }

    public void setShowNavigationArrows(boolean showNavigationArrows) {
        this.showNavigationArrows = showNavigationArrows;
        updateNavigationArrows(showNavigationArrows);
    }

    public void updateNavigationArrows(boolean showNavigationArrows) {
        if (showNavigationArrows) {
            leftArrowButton.setVisibility(View.VISIBLE);
            rightArrowButton.setVisibility(View.VISIBLE);
        } else {
            leftArrowButton.setVisibility(View.INVISIBLE);
            rightArrowButton.setVisibility(View.INVISIBLE);
        }
    }
    
    public boolean isEnableSwipe() {
        return enableSwipe;
    }

    public void setEnableSwipe(boolean enableSwipe) {
        this.enableSwipe = enableSwipe;
        viewPager.setEnabled(enableSwipe);
    }
    
    public boolean isFitAllMonths() {
        return fitAllMonths;
    }
    
    /**
     * A calendar height is not fixed, it may have 5 or 6 rows. Set fitAllMonths
     * to true so that the calendar will always have 6 rows
     */
    public void setFitAllMonths(boolean fitAllMonths) {
        this.fitAllMonths = fitAllMonths;
        viewPager.setFitAllMonths(fitAllMonths);
    }
    
    public void setCaldroidListener(CaldroidListener caldroidListener) {
        this.caldroidListener = caldroidListener;
    }


    /**
     * DatePageChangeListener refresh the date grid views when user swipe the
     * calendar
     */
    private class DatePageChangeListener implements OnPageChangeListener {
        
        private int currentPage = InfiniteViewPager.OFFSET;

        /**
         * Return currentPage of the dateViewPager
         * @return
         */
        public int getCurrentPage() {
            return currentPage;
        }

        /**
         * Return virtual next position
         * @param position
         * @return
         */
        private int getNext(int position) {
            return (position + 1) % NUMBER_OF_PAGES;
        }

        /**
         * Return virtual previous position
         * @param position
         * @return
         */
        private int getPrevious(int position) {
            return (position + 3) % NUMBER_OF_PAGES;
        }

        /**
         * Return virtual current position
         * @param position
         * @return
         */
        public int getCurrent(int position) {
            return position % NUMBER_OF_PAGES;
        }

        @Override
        public void onPageScrollStateChanged(int position) {
        }

        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) {
        }
        
        /**
         * 刷新当前页面数据
         */
        public void refreshAdapters() {
            refreshAdapters(currentPage);
        }

        /**
         * 刷新分页数据
         */
        public void refreshAdapters(int position) {
            // Get adapters to refresh
            curGridAdapter = pagerAdapters.get(getCurrent(position));
            CaldroidGridAdapter prevAdapter = pagerAdapters .get(getPrevious(position));
            CaldroidGridAdapter nextAdapter = pagerAdapters.get(getNext(position));

            if (position == currentPage) {
                // 刷新当前界面
                curGridAdapter.setAdapterDateTime(curPageDateTime, startDayOfWeek);

                // 刷新上一页
                prevAdapter.setAdapterDateTime(curPageDateTime.minus(0, 1, 0, 0, 0, 0, 0, DateTime.DayOverflow.LastDay), 
                    startDayOfWeek);

                // 刷新下一页
                nextAdapter.setAdapterDateTime(curPageDateTime.plus(0, 1, 0, 0,0, 0, 0, DateTime.DayOverflow.LastDay), 
                    startDayOfWeek);
            }
            
            else if (position > currentPage) {
                // 右滑了
                //当前时间改变了
                curPageDateTime = curPageDateTime.plus(0, 1, 0, 0, 0, 0, 0,DateTime.DayOverflow.LastDay);
                monthChanged();

                // 刷新下一页
                nextAdapter.setAdapterDateTime(curPageDateTime.plus(0, 1, 0, 0,0, 0, 0, DateTime.DayOverflow.LastDay), 
                    startDayOfWeek);
            }
            
            else {
                // 左滑了
                //当前时间改变了
                curPageDateTime = curPageDateTime.minus(0, 1, 0, 0, 0, 0, 0,DateTime.DayOverflow.LastDay);
                monthChanged();

                // 刷新上一页
                prevAdapter.setAdapterDateTime(curPageDateTime.minus(0, 1, 0, 0, 0, 0, 0, DateTime.DayOverflow.LastDay), 
                    startDayOfWeek);
            }

            // Update current page
            currentPage = position;
        }

        /**
         * Refresh the fragments
         */
        @Override
        public void onPageSelected(int position) {
            refreshAdapters(position);
        }

    }
    
}
